//##################################################################################################
(function(WIN, DOC, NAV){                                                           // BEGIN LIBRARY
//##################################################################################################

/**
 * Internal constants & variables
 * @private 
 */
var OBJ = Object.prototype, 
    ARR = Array.prototype,
    STR = String.prototype,
    FUN = Function.prototype,
    COMPAT = !(WIN.attachEvent && !WIN.opera);

/**
 * Constructs a new instance of iOne object with given parameter.<br>
 * The 'new' keyword is not required to create an object since it already<br>
 * contains an lazy instantiation mechanism. Using different parameter types<br>
 * will effect the functionality of internal CSS Selector Engine as follows:<br>
 *  - selector text -> iOne with selected dom element(s)<br>
 *  - dom element   -> iOne with given element<br>
 * @param {String|HTMLElement} o
 * @param {HTMLElement} root
 * @return {iOne}
 */
var iOne = function(o, root){
    // create an instance or use cached one
    if(!(this instanceof iOne)) {
        var id = (node(o) == 1 || node(o) == 9) ? o.guid || (o.guid = guid++) : 0;
        o = is.string(o) ? (id = o.replace(/^\s+|\s+$/, '')) : o;
        return cache[id] || (cache[id] = new iOne(o, root));
    }
    // add single node element or query for it first
    //if(COMPAT) ARR.push.apply(this, node(o) ? [o] : node.select(o, root));
    //return extend(this, node(o) ? [o] : node.select(o, root));
    return this;
};


//--------------------------------------------------------------------------------------------------
// MODULE : is || iOne.is
//--------------------------------------------------------------------------------------------------
/**
 * Provides a shortcut to get string representation of any given variable <br/>
 * and it also contains sub methods to check specific variable types <br/>
 * (primitive and/or reference) such as String, Number Object etc..
 * @global
 */
var is = iOne.is = (function(){
    /**
     * Returns the string representation of given variable type.
     * @param {Object} o Variable that will be converted to string to get type.
     * @return {String} String representation of given variable.
     */
    var is = function(o){
        return is.undef(o) ? 'null' : o.nodeType ? 'node'
            : (o.setInterval || o.userAgent || o.log) ? 'global'
            : OBJ.toString.call(o).toLowerCase().replace(/\[.*\s(\w+)\]/, '$1');
    };
    /**
     * Determines if given variable is undefined or null.
     * @param {Object} o Variable to be checked.
     * @return {Boolean} Result of test
     */
    is.undef = function(o){return typeof o === 'undefined' || o == null};
    /**
     * Determines if given variable is a string.
     * @param {Object} o Variable to be checked.
     * @return {Boolean} Result of test.
     */    
    is.string = function(o){return OBJ.toString.call(o) == '[object String]'};
    /**
     * Determines if given variable is a boolean.
     * @param {Object} o Variable to be checked.
     * @return {Boolean} Result of test.
     */    
    is.bool = function(o){return OBJ.toString.call(o) == '[object Boolean]'};
    /**
     * Determines if given variable is an array.
     * @param {Object} o Variable to be checked.
     * @return {Boolean} Result of test.
     */    
    is.array = function(o){return OBJ.toString.call(o) == '[object Array]'};
    /**
     * Determines if given variable is a function.
     * @param {Object} o Variable to be checked.
     * @return {Boolean} Result of test.
     */       
    is.func = function(o){return OBJ.toString.call(o) == '[object Function]'};
    /**
     * Determines if given variable is a number but not NaN.
     * @param {Object} o Variable to be checked.
     * @return {Boolean} Result of test.
     */       
    is.number = function(o){return OBJ.toString.call(o) == '[object Number]' && !isNaN(o)};
    /**
     * Determines if given variable is an object but not an DOM element.
     * @param {Object} o Variable to be checked.
     * @return {Boolean} Result of test.
     */       
    is.object = function(o){return OBJ.toString.call(o) == '[object Object]' && !o.nodeType};
    return is;
})();


//--------------------------------------------------------------------------------------------------
// MODULE : now || iOne.now
//--------------------------------------------------------------------------------------------------
/**
 * Returns current date object or formatted date based on given string.
 * @global
 * @param {String} f Optional format string to get formatted date string.
 * @return {String|Date} Formatted date string or raw Date object.
 */
var now = iOne.now = (function(){
    var d, get = {
        hh: function(){return d.getHours()},
        mm: function(){return d.getMinutes()},
        ss: function(){return d.getSeconds()},
        t : function(){return d.getTime()},
        d : function(){return d.getDate()},
        m : function(){return d.getMonth()},
        y : function(){return d.getFullYear()}
    };
    return function(f){
        d = new Date(); 
        if(is.string(f)) for(var k in get) f = f.replace(k, get[k]); 
        return f || d;
    }
})();


//--------------------------------------------------------------------------------------------------
// MODULE : log || iOne.log
//--------------------------------------------------------------------------------------------------
/**
 * Prints an given string in browser's console if exist or stores everything into an internal <br/> 
 * cache object to be outputed or exported later on the screen using log.dump method.
 * @global
 */
var log = iOne.log = (function(){
    var cache = {},
    /**
     * Logs an output directly onto the browser's console if available or stores into log cache.
     * @param {Object} Any time of variable to be logged including Arrays.
     */
    log = WIN.console ? 
        function(o){console.log(now('[hh:mm:ss] : ') + o)} : 
        function(o){cache[now('hh:mm:ss')] = o};
    /**
     * Returns the full cached logs with timestamped keys.
     * @returns {Object}
     */
    log.dump = function(){DOC.write(cache)};
    return log;
})();


//--------------------------------------------------------------------------------------------------
// MODULE : node
//--------------------------------------------------------------------------------------------------
/**
 * Contains necessary DOM manipulation methods for nodes that support cross browser <br/>
 * compatibility such as create, bind, get & set etc for internal use inside the iOne library. <br/>
 * @private
 */
var node = iOne.node = (function(){
    // attribute translations
    var map = {
        'class': 'className',
        'for': 'htmlFor'        
    },
    // selector patterns 
    reg = {
        id: /^#(\w+(?:\-\w+)?)$/,
        tag: /^(\*|[a-zA-Z]+)$/,
        name: /^\[name\=(\w+(?:\-\w+)?)\]$/,
        clas: /^(?:\.(\w+(?:\-\w+)?))|(?:\[class\=(\w+(?:\-\w+)?)\])/        
    },
    // NodeList to array converter
    slice = COMPAT ? 
        function(o){return ARR.slice.call(o, 0)} :
        function(o){var i = o.length, a = new Array(i); while(i--) a[i] = o[i]; return a},
    /**
     * Returns the type of given node if it is a valid node. Otherwise 0 will be <br/>
     * returned which can be evoluated to determine whether given variable is a node or not.
     * @param {Object} n Node object.
     * @return {Number} Integer representation of node type.
     */
    node = function(n){ return n && n.nodeType || 0};
    /**
     * @param {Object} n Node object.
     * @param {String} e Event name.
     * @param {Function} fn Function to bind on specified event.
     * @return {Boolean} Result of event binding as true or false on failure.
     */
    node.bind = COMPAT ?
        function(n, e, fn){return n && n.addEventListener(e, fn, false)} :
        function(n, e, fn){return n && n.attachEvent('on' + e, function(){fn.call(this)})};    
    /**
     * Creates a new node and returns it after appliying it into specified parent element.
     * @param {String} s Node string to create.
     * @param {Object} n Parent node to be added. (document by default).
     * @return {Object} Newly created node.
     */
    node.create = function(s, n){};
    /**
     * Gets or sets an attribute with specified key or null on failure.
     * @param {Object} n Node object.
     * @param {String} k Attribute key.
     * @param {Object} v Attribute value (optional).
     * @return {Object} New value of specified attribute.
     */
    node.attribute = function(n, k, v){
        return !n ? null : (typeof v === 'undefined') ?
            (n.getAttribute(map[k] || k) || n[map[k] || k]) : 
            (n.setAttribute(map[k] || k, v) || (n[map[k] || k] = v))
    };
    /**
     * Gets or sets a style property with specified key or null on failure.
     * @param {Object} n Node object.
     * @param {String} k Style property key.
     * @param {Object} v Style property value (optional).
     * @return {Object} New value of specified style property.
     */    
    node.style = function(n, k, v){
        return !n ? null : (typeof v === 'undefined') ? 
            n.style[map[k] || k] : (n.style[map[k] || k] = v)
    };    
    /**
     * Returns an array containing a single node or set of nodes depending on the selector(s) <br/>
     * being queried. If native methods are not supported then result will be produced by <br/>
     * iOne's own CSS selector engine implementation to ensure compability with older browsers.
     * @param {String} s Selector query.
     * @param {Object} root Root of the elements (document by default).
     * @return {Array} Resulting array with selected node(s).
     */
    node.select = function(s, root){
        if(s === '') return [];                                                 // TODO: merge all into compact conditional structure
        if(root && node(root) != 1) return []; root = DOC; var m;      
        if((m = reg.id.exec(s))) return [DOC.getElementById(m[1])];
        if(DOC.getElementsByClassName && (m = reg.clas.exec(s)))
            return slice(root.getElementsByClassName(m[2] || m[1]));    
        if((m = reg.name.exec(s))) return slice(root.getElementsByName(m[1]));
        if((m = reg.tag.exec(s))) return slice(root.getElementsByTagName(m[1]));
        if(DOC.querySelectorAll) return slice(root.querySelectorAll(s));        // TODO: implement non-standard CSS engine
        return [];        
    };
    return node;
})();




//##################################################################################################
WIN.iOne = WIN.io = iOne})(window, window.document, window.navigator);             // END OF LIBRARY
//##################################################################################################